package com.zq.widget.inverted.game;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.animation.AnimationUtils;

import com.zq.widget.inverted.R;
import com.zq.widget.inverted.game.role.Role;
import com.zq.widget.inverted.game.role.damage.DamageCollisionHandler;
import com.zq.widget.inverted.game.role.equipment.weapon.gun.Gun2;
import com.zq.widget.inverted.game.role.impl.plane.HeroPlane;
import com.zq.widget.inverted.game.role.RoleRoot;
import com.zq.widget.inverted.game.role.impl.plane.Plane;
import com.zq.widget.inverted.game.role.impl.plane.Plane2;
import com.zq.widget.inverted.game.role.impl.plane.PlaneBoss;
import com.zq.widget.inverted.game.role.impl.prop.PropRole;
import com.zq.widget.inverted.game.role.impl.prop.WeaponUpLevel;

import java.util.concurrent.atomic.AtomicBoolean;

/**
 * Created by zhangqiang on 2018/3/28.
 */
public class GameView extends SurfaceView implements SurfaceHolder.Callback {

    private Thread computeThread = new ComputeThread();
    private AtomicBoolean isRunning = new AtomicBoolean();
    private SurfaceHolder mHolder;
    private RoleRoot roleRoot;
    private Bitmap bgBitmap;
    private float bgMoveVelocity = 200;
    private Paint mPaint = new Paint();
    HeroPlane heroPlane;


    public GameView(Context context) {
        super(context);
        init(context);
    }

    public GameView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public GameView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public GameView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context);
    }

    private void init(Context context) {

        mHolder = getHolder();
        mHolder.addCallback(this);
        roleRoot = new RoleRoot(context);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        isRunning.set(true);
        computeThread.start();
        heroPlane = new HeroPlane(getContext(), R.drawable.hero_plane, 100);
        heroPlane.updateLocation(getWidth()/2,getHeight() - heroPlane.bounds().height());
        roleRoot.addChild(heroPlane);
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        isRunning.set(false);
    }

    private float mLastX, mLastY;
    private Role mTouchTarget;

    @SuppressLint("ClickableViewAccessibility")
    @Override
    public boolean onTouchEvent(MotionEvent event) {


        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:

                mTouchTarget = null;
                mLastX = event.getX();
                mLastY = event.getY();
                mTouchTarget = findRoleAt(mLastX, mLastY);
                break;
            case MotionEvent.ACTION_MOVE:

                float x = event.getX();
                float y = event.getY();
                mTouchTarget.locationOffset(x - mLastX, y - mLastY);
                mLastX = x;
                mLastY = y;
                break;
        }
        return mTouchTarget != null;
    }

    private class ComputeThread extends Thread {

        private long startTime, pastTime;
        private long currentTimeMillis;
        private long lastEnemyTime;
        private long lastBossTime;
        private long lastPropTime;
        private long lastPlaneGroupTime;

        @Override
        public void run() {
            super.run();

            startTime = AnimationUtils.currentAnimationTimeMillis();

            while (isRunning.get()) {

                Canvas canvas = mHolder.lockCanvas();
                if (canvas == null) {
                    break;
                }
                //清屏
                canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);

                currentTimeMillis = AnimationUtils.currentAnimationTimeMillis();
                pastTime = currentTimeMillis - startTime;

                drawBackground(canvas);

                roleRoot.preDraw();
                roleRoot.draw(canvas);
                roleRoot.computeCollision();
                compute();

                drawPoint(canvas);

                if(heroPlane.isFinish()){
                    isRunning.set(false);
                    drawGameOver(canvas);
                }

                mHolder.unlockCanvasAndPost(canvas);


            }
        }

        private void drawGameOver(Canvas canvas) {

            canvas.drawColor(Color.BLACK);
            mPaint.reset();
            float textSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 30, getResources().getDisplayMetrics());
            mPaint.setAntiAlias(true);
            mPaint.setTextSize(textSize);
            mPaint.setColor(Color.RED);
            String pointText = "Game Over!!";
            float textWidth = mPaint.measureText(pointText);
            canvas.drawText(pointText,getWidth()/2 - textWidth/2,getHeight()/2 + mPaint.ascent(),mPaint);
        }

        private void drawPoint(Canvas canvas) {

            mPaint.reset();
            float textSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 20, getResources().getDisplayMetrics());
            mPaint.setAntiAlias(true);
            mPaint.setTextSize(textSize);
            String pointText = "分数：" + ((DamageCollisionHandler) heroPlane.getCollisionHandler()).getPoint();
            float textWidth = mPaint.measureText(pointText);
            canvas.drawText(pointText,getWidth() - textWidth,-mPaint.ascent(),mPaint);
        }

        private void drawBackground(Canvas canvas) {

            int width = canvas.getWidth();

            if (bgBitmap == null) {
                bgBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.bg4);
                int bWidth = bgBitmap.getWidth();
                int bHeight = bgBitmap.getHeight();
                float sizeScaleFactor = (float) width / bWidth;
                float scaleBitmapHeight = bHeight * sizeScaleFactor;
                bgBitmap = Bitmap.createScaledBitmap(bgBitmap, width, (int) scaleBitmapHeight, true);
            }

            int bHeight = bgBitmap.getHeight();

            float bgOffset = (float) pastTime / 1000 * bgMoveVelocity % (bHeight);

            mPaint.reset();
            mPaint.setAntiAlias(true);

            int save1 = canvas.save();
            canvas.translate(0, -bgOffset);
            canvas.drawBitmap(bgBitmap, 0, 0, mPaint);
            canvas.translate(0, bHeight);
            canvas.drawBitmap(bgBitmap, 0, 0, mPaint);
            canvas.restoreToCount(save1);
        }


        private void compute() {

            long enemyTime = currentTimeMillis - lastEnemyTime;
            long bossTime = currentTimeMillis - lastBossTime;
            long propTime = currentTimeMillis - lastPropTime;
            long planeGroupTime = currentTimeMillis - lastPlaneGroupTime;

            if (enemyTime > 3000) {

                int count;
                if(pastTime < 10 * 1000){
                    count = 1;
                }else if(pastTime < 30 * 1000){
                    count = 2;
                }else {
                    count = 3;
                }
                for (int i = 0; i < count; i++) {
                    Plane role = new Plane(getContext(), R.drawable.a4_1, 0, randomY(), getWidth(), randomY(), 5000);
                    role.addEquipment(new Gun2());
                    roleRoot.addChild(role);
                }
                lastEnemyTime = currentTimeMillis;
            }
            if(pastTime > 60 * 1000 && bossTime > 30 * 1000){

                roleRoot.addChild(new PlaneBoss(getContext(),0,randomY(),getWidth(),randomY()));
                lastBossTime = currentTimeMillis;
            }

            if(propTime > 10 * 1000){

//                roleRoot.addChild(new PropRole(getContext(),randomX(),randomY(),200,new LaserGun(10 * 1000)));
                roleRoot.addChild(new PropRole(getContext(),randomX(),randomY(),200, 10 * 1000, new WeaponUpLevel(0,1)));
                lastPropTime = currentTimeMillis;
            }
            if(planeGroupTime > 10 * 1000){

                for (int i = 0; i < 6; i++) {
                    roleRoot.addChild(new Plane2(getContext(), R.drawable.a4_3, 0, getHeight()/2, 180,150, 60 * i, 150,0));
                }
                lastPlaneGroupTime = currentTimeMillis;
            }
        }
    }



    private float randomX() {

        return (float) (getWidth() * Math.random());
    }

    private float randomY() {

        return (float) (getHeight() * 0.5f * Math.random());
    }

    private Role findRoleAt(float x, float y) {

        int childCount = roleRoot.getChildCount();
        for (int i = 0; i < childCount; i++) {

            Role role = roleRoot.getChildAt(i);
            boolean contains = role.bounds().contains(x, y);
            if (contains) {
                return role;
            }
        }
        return null;
    }
}
